#IF REGISTERED
CHECKSUM DW ?
BYTES_TO_SAVE EQU 260+2
     R1:JMP RESTORESCREEN
LOADGAME:
        LEA SI,LOADMSG
        CALL FILEWINDOW
        CMP AL,3
        JE R1
        CMP AL,27
        JE R1
        MOV AH,09E
        LEA SI,LOADINGMSG
        MOV DI,01000*HELP_TXTPG+12*160+35*2
        CALL PRINTSTRING
        MOV AX,03D BY 11000000xB
        LEA DX,FILENAME
        INT 021   ; open file
        JNC LOAD_OK
        CMP AX,2
        JE LOAD_NOTFOUND
        CMP AX,3
        JNE >E1
LOAD_NOTFOUND:
        CALL ERASEWINDOW
        LEA SI,NOTFOUNDMSG
        JMP >E2
     E1:
        LEA SI,LOADFAILMSG
     E2:
        MOV AH,09C
        MOV DI,01000*HELP_TXTPG+11*160+32*2
        CALL PRINTSTRING
PRESSANYKEY:
        MOV AH,09F
        LEA SI,PRESSAKEYMSG
        MOV DI,01000*HELP_TXTPG+12*160+33*2
        CALL PRINTSTRING
        MOV AH,03E
        INT 021  ; close file
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,12 BY 46
        INT 010   ; place cursor
        MOV AH,0
        INT 016
        JMP RESTORESCREEN
LOAD_OK:
        MOV BX,AX   ; save handle
        MOV CX,BYTES_TO_SAVE
        MOV BP,SP
        SUB SP,CX
        MOV DX,SP
        MOV AH,03F
        INT 021   ; load from disk
        JNC >L0
     F0:
        MOV SP,BP
        MOV AH,03E
        INT 021    ; close file
        CALL ERASEWINDOW
        JMP E1
     L0:
        CMP AX,CX
        JNE F0
        MOV AH,03E
        INT 021     ; close file
        MOV DI,SP
;
        MOV CHECKSUM,0
        MOV SI,OBJECT
        MOV CX,21
     L1:
        CALL READ_AX
        MOV RM,AX
        CALL READ_AX
        MOV LOC,AX
        CMP SI,DRAGON
        JB >L2
        CALL READ_AX
        MOV W[SI+4],AX
        ADD SI,DRSZ-OSZ
     L2:
        ADD SI,OSZ
        LOOP L1
;
        CALL READ_AX
        MOV ROOM,AX
        MOV LASTGOOD_RM,AX
        CALL READ_AX
        MOV PL_AD,AX
        MOV LASTGOOD_AD,AX
;        
        CALL READ_AX
        MOV MOVEMODE,AH
        MOV SOUND?,0
        TEST AL,080
        IF NZ NOT SOUND?
        AND AL,07F
        MOV GAMENO,AL
        CALL READ_AX
        MOV JLEFT,AX
        CALL READ_AX
        MOV JRIGHT,AX
        CALL READ_AX
        MOV JUP,AX
        CALL READ_AX
        MOV JDOWN,AX
        CALL READ_AX
        MOV START_JOYVALS,AX
        CALL READ_AX
        MOV START_JOYVALS[2],AX
;
        CALL READ_AX
        MOV W[OFFSET LDIF],AX
        CALL READ_AX
        MOV CARRYING,AX
        CALL READ_AX
        MOV CARRY_DISTANCE,AX
        CALL READ_AX
        MOV SWALLOWED,AX
        CALL READ_AX
        MOV BAT_CARRYING,AX
        CALL READ_AX
        MOV BAT_CD,AX
        CALL READ_AX
        MOV W[OFFSET SWCARBYBAT_BG],AX
;
        CALL READ_AX
        MOV SHOWDIF_CNT,AL
        MOV GATE[0],0
        MOV GATE[1],0
        MOV GATE[2],0
        MOV GATE[3],0
        MOV GATE[4],0
        TEST AH,080
        IF NZ NOT GATE[0]
        TEST AH,040
        IF NZ NOT GATE[1]
        TEST AH,020
        IF NZ NOT GATE[2]
        TEST AH,010
        IF NZ NOT GATE[3]
        TEST AH,8
        IF NZ NOT GATE[4]
;
        CALL READ_AX_DONTADD
        CMP AX,CHECKSUM
        IF NE JMP EXIT_PROGRAM
;
        MOV SP,BP
        MOV PROG_JUST_STARTED?,0
        MOV ES,AX,VIDSEG_MAIN
        MOV DI,0F00
        MOV AX,0720
        MOV CX,80
        REP STOSW   ; erase bottom line
        CALL PUTROOM
;        
RESTORESCREEN:
        CMP SOUND?,0
        JE >S1
        CMP SOUND_PTR,0
        JE >S1
        IN AL,061
        OR AL,3
        OUT 061,AL
     S1:
        MOV AX,5 BY MAIN_TXTPG
        INT 010     ; back to text page 0
        RET
READ_AX:
        MOV DX,[DI]
        MOV AX,[DI+2]
        CALL DSKDECODE
        ADD DI,4
        ADD CHECKSUM,AX
        RET
READ_AX_DONTADD:
        MOV DX,[DI]
        MOV AX,[DI+2]
        CALL DSKDECODE
        ADD DI,4
        RET
PRINTSTRING:   ; expects AH=attribute, SI=string, DI=screen addr
        LODSB
        CMP AL,0
        JE >P1
        STOSW
        JMP PRINTSTRING
     P1:
        RET
     R1:JMP RESTORESCREEN
SAVEGAME:
        LEA SI,SAVEMSG
        CALL FILEWINDOW
        CMP AL,3
        JE R1
        CMP AL,27
        JE R1
        MOV AH,09E
        LEA SI,SAVINGMSG
        MOV DI,01000*HELP_TXTPG+12*160+35*2
        CALL PRINTSTRING
        MOV AH,03C
        MOV CX,0
        LEA DX,FILENAME
        INT 021   ; open file
        JNC SAVE_OK
        CALL ERASEWINDOW
        CMP AX,3
        JNE >S1
        LEA SI,PATHNOTFOUNDMSG
        JMP >S2
     S1:
        LEA SI,CANNOTOPENMSG
     S2:
        MOV AH,09E
        MOV DI,01000*HELP_TXTPG+11*160+32*2
        CALL PRINTSTRING
        JMP PRESSANYKEY
SAVE_OK:
        MOV BX,AX  ; save handle
        MOV CHECKSUM,0
; First, save objects to memory
        MOV BP,SP
        SUB SP,BYTES_TO_SAVE
        MOV DI,SP   ; save buffer
        MOV SI,OBJECT
        MOV CX,21
    S10:
        MOV AX,RM
        CALL WRITE_AX
        MOV AX,LOC
        CALL WRITE_AX
        CMP SI,DRAGON
        JB >S11
        MOV AX,W[SI+4]  ; HINC & VINC of dragons, bat
        CALL WRITE_AX
        ADD SI,DRSZ-OSZ
    S11:
        ADD SI,OSZ
        LOOP S10
;
        MOV AX,ROOM
        CALL WRITE_AX
        MOV AX,PL_AD
        CALL WRITE_AX
;
        MOV AH,MOVEMODE
        MOV AL,GAMENO
        CMP SOUND?,0
        IF NE OR AL,080
        CALL WRITE_AX
        MOV AX,JLEFT
        CALL WRITE_AX
        MOV AX,JRIGHT
        CALL WRITE_AX
        MOV AX,JUP
        CALL WRITE_AX
        MOV AX,JDOWN
        CALL WRITE_AX
        MOV AX,START_JOYVALS
        CALL WRITE_AX
        MOV AX,START_JOYVALS[2]
        CALL WRITE_AX
        MOV AX,W[OFFSET LDIF]
        CALL WRITE_AX
        MOV AX,CARRYING
        CALL WRITE_AX
        MOV AX,CARRY_DISTANCE
        CALL WRITE_AX
        MOV AX,SWALLOWED
        CALL WRITE_AX
        MOV AX,BAT_CARRYING
        CALL WRITE_AX
        MOV AX,BAT_CD
        CALL WRITE_AX
        MOV AX,W[OFFSET SWCARBYBAT_BG]
        CALL WRITE_AX
;
        MOV AL,SHOWDIF_CNT
        MOV AH,0
        CMP GATE[0],0
        IF NE OR AH,080
        CMP GATE[1],0
        IF NE OR AH,040
        CMP GATE[2],0
        IF NE OR AH,020
        CMP GATE[3],0
        IF NE OR AH,010
        CMP GATE[4],0
        IF NE OR AH,8
        CALL WRITE_AX
;
        MOV AX,CHECKSUM
        CALL WRITE_AX
        CALL RANDNUM
        MOV [DI],AX
        ADD DI,2
;
        MOV AH,040
        MOV CX,BYTES_TO_SAVE
        LEA DX,[DI-BYTES_TO_SAVE]
        INT 021   ; do save
        MOV SP,BP
        JNC WRITE_OK
        CALL ERASEWINDOW
        MOV AH,09E
        LEA SI,SAVEFAILMSG
        MOV DI,01000*HELP_TXTPG+11*160+34*2
        CALL PRINTSTRING
        JMP PRESSANYKEY
WRITE_OK:
        CMP AX,CX
        JE >S20
        CALL ERASEWINDOW
        LEA SI,DISKFULLMSG
        MOV DI,01000*HELP_TXTPG+11*160+35*2
        CALL PRINTSTRING
        JMP PRESSANYKEY
    S20:
        MOV AH,03E
        INT 021  ; close file
        JMP RESTORESCREEN
WRITE_AX:
        ADD CHECKSUM,AX
        CALL DSKENCODE
        MOV [DI],DX
        MOV [DI+2],AX
        ADD DI,4
        RET
ERASEWINDOW:
        PUSH AX,BX,CX,DX
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,11 BY 6
        INT 010         ; position cursor...
        MOV AX,9 BY ' '
        MOV BX,HELP_TXTPG BY 09E
        MOV CX,68
        INT 010         ; ...and fill first row
     E2:
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,12 BY 6
        INT 010         ; position cursor...
        MOV AX,9 BY ' '
        MOV BX,HELP_TXTPG BY 090
        MOV CX,68
        INT 010         ; ...and fill second row
        POP DX,CX,BX,AX
        RET
ERASE_2ND_ROW:
        PUSH AX,BX,CX,DX
        JMP E2
FILENAME DB 64 DUP ?
FILEWINDOW:
        IN AL,061
        AND AL,0FC
        OUT 061,AL
        PUSH DS,SI
        MOV DS,AX,VIDSEG_MAIN
        MOV ES,AX
        MOV SI,0
        MOV DI,01000*HELP_TXTPG    ; addr of page 2
        MOV CX,80*25
        REP MOVSW
        POP SI,DS
;        
        MOV W[ES:01000*HELP_TXTPG+160*10+4*2],0    ; UL corner
        MOV DI,01000*HELP_TXTPG+160*10+5*2
        MOV CX,70
        MOV AX,03DC
        REP STOSW             ; top edge
        MOV W[ES:DI],0               ; UR corner
        MOV W[ES:01000*HELP_TXTPG+160*13+4*2],0  ; LL corner
        MOV DI,01000*HELP_TXTPG+160*13+5*2
        MOV CX,70
        MOV AX,03DF
        REP STOSW             ; bottom edge
        MOV W[ES:DI],0        ; LR corner
        MOV W[ES:01000*HELP_TXTPG+160*11+8],0
        MOV W[ES:01000*HELP_TXTPG+160*12+8],0
        MOV W[ES:01000*HELP_TXTPG+160*11+150],0
        MOV W[ES:01000*HELP_TXTPG+160*12+150],0
        MOV W[ES:01000*HELP_TXTPG+160*11+10],03DB
        MOV W[ES:01000*HELP_TXTPG+160*12+10],03DB
        MOV W[ES:01000*HELP_TXTPG+160*11+148],03DB
        MOV W[ES:01000*HELP_TXTPG+160*12+148],03DB
        CALL ERASEWINDOW
        MOV AX,5 BY HELP_TXTPG  ; text page 2
        INT 010
;
        MOV AH,09E
        MOV DI,01000*HELP_TXTPG+160*11+26*2
        CALL PRINTSTRING
        MOV DL,8   ; starting point of cursor
FWLOOP:
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DH,12
        INT 010    ; place cursor
        CMP CTRL_BRK_PRESSED?,0
        IF NE JMP EXIT_PROGRAM
        MOV AH,0
        INT 016    ; get key
        CMP AL,3
        JE FW_DONE
        CMP AL,27
        JE FW_DONE
        CMP AL,8
        JE >F1
        CMP AL,127
        JE >F1
        CMP AX,'S' BY 0   ; Delete key
        JNE >F2
     F1:   ; delete a character
        CMP DL,8
        JE FWLOOP
        DEC DL
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DH,12
        INT 010    ; place cursor
        MOV AX,0A BY ' '
        MOV BX,HELP_TXTPG BY 0
        MOV CX,1
        INT 010    ; erase character
        JMP FWLOOP
     F2:
        CMP AL,13
        JE FW_DONE
        CMP DL,8+64
        JNE >F3
        PUSH DX
        MOV AH,6
        MOV DL,7  ; bell
        INT 021
        POP DX
        JMP FWLOOP
     F3:
;  insert normal character
        CMP AL,32
        JB FWLOOP
        MOV AH,0A
        MOV BX,HELP_TXTPG BY 0
        MOV CX,1
        INT 010   ; show character
        INC DL
        JMP FWLOOP
FW_DONE:
        PUSH AX
        MOV SI,01000*HELP_TXTPG+12*160+8*2
        LEA DI,FILENAME
        MOV CL,DL
        MOV CH,0
        SUB CL,8
        JZ >F10
     F9:
        LODS W[ES:SI]
        MOV [CS:DI],AL
        INC DI
        LOOP F9
     F10:
        MOV B[CS:DI],0  ; terminate filename
        CALL FORCE_EXTENSION
        CALL ERASE_2ND_ROW
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,12 BY 46  ; position cursor
        INT 010
        POP AX   ; AL will contain terminating key
        RET
FORCE_EXTENSION:
        MOV AL,'.'
        LEA DI,FILENAME
        PUSH ES
        MOV ES,CS
    F20:
        CMP B[DI],0
        JE >F22
        SCASB
        JNE F20
    F21:
        POP ES
        RET
    F22:    ; no period found in filename, so add .ADV extension
        LEA SI,DEFAULT_EXTENSION
        MOV CX,5
        REP MOVSB
        JMP F21
DSKENCODE:   ; entry:  AX    exit:   AX, DX
        PUSH CX
        CALL ENCEXPAND
        PUSH AX
        PUSH DX
        CALL RANDNUM
        CALL ENCEXPAND
        SHR AX,1
        SHR DX,1
        POP CX
        OR DX,CX
        POP CX
        OR AX,CX
        POP CX
        RET
ENCEXPAND:   ; entry:  AX    exit:   AX, DX
        MOV DX,0
        TEST AH,080
        IF NZ OR DH,080
        TEST AH,040
        IF NZ OR DH,020
        TEST AH,020
        IF NZ OR DH,8
        TEST AH,010
        IF NZ OR DH,2
        TEST AH,8
        IF NZ OR DL,080
        TEST AH,4
        IF NZ OR DL,020
        TEST AH,2
        IF NZ OR DL,8
        TEST AH,1
        IF NZ OR DL,2
        MOV AH,0
        TEST AL,080
        IF NZ OR AH,080
        TEST AL,040
        IF NZ OR AH,020
        TEST AL,020
        IF NZ OR AH,8
        TEST AL,010
        IF NZ OR AH,2
        AND AL,0F
        TEST AL,8
        IF NZ OR AL,080
        TEST AL,4
        IF NZ OR AL,020
        TEST AL,2
        PUSHF
        AND AL,0F1
        POPF
        IF NZ OR AL,8
        TEST AL,1
        PUSHF
        AND AL,0FE
        POPF
        IF NZ OR AL,2
        RET
DSKDECODE:   ; entry:  AX,DX   exit: AX
        PUSH CX
        MOV CX,0
        TEST DH,080
        IF NZ OR CH,080
        TEST DH,020
        IF NZ OR CH,040
        TEST DH,8
        IF NZ OR CH,020
        TEST DH,2
        IF NZ OR CH,010
        TEST DL,080
        IF NZ OR CH,8
        TEST DL,020
        IF NZ OR CH,4
        TEST DL,8
        IF NZ OR CH,2
        TEST DL,2
        IF NZ OR CH,1
        TEST AH,080
        IF NZ OR CL,080
        TEST AH,020
        IF NZ OR CL,040
        TEST AH,8
        IF NZ OR CL,020
        TEST AH,2
        IF NZ OR CL,010
        TEST AL,080
        IF NZ OR CL,8
        TEST AL,020
        IF NZ OR CL,4
        TEST AL,8
        IF NZ OR CL,2
        TEST AL,2
        IF NZ OR CL,1
        MOV AX,CX
        POP CX
        RET
#ENDIF
#IF 1
JOYSTICK_CHECKS EQU 4           ; actually log-base-2 of number of checks 
JOYSTICK_INIT:
        MOV START_JOYVALS,0FFFF
        MOV START_JOYVALS[2],0FFFF
        MOV CX,1 SHL JOYSTICK_CHECKS
        XOR AX,AX
        XOR BX,BX
     J1:
        PUSH AX,BX,CX
        CALL JOYSTICK
        POP CX,BX,AX
        JC >J3
        ADD AX,HMOV
        ADD BX,VMOV
        LOOP J1         ; add up
        MOV CL,JOYSTICK_CHECKS
        SHR AX,CL       ; divide to get average
        SHR BX,CL
        MOV HMOV,AX
        MOV VMOV,BX
        OR AX,BX
        JZ >J3          ; both zero, something's wrong
     J2:
        DMOV START_JOYVALS,JOYVALS
;
        MOV AX,HMOV     ; assuming joystick is in the middle...
        PUSH AX
        SHR AX,1        ; ...find one-fourth point
        MOV JLEFT,AX
        POP BX
        ADD AX,BX       ; « + ¬ = 3/4
        MOV JRIGHT,AX ; ...and find three-fourths point
        MOV AX,VMOV
        PUSH AX
        SHR AX,1
        MOV JUP,AX
        POP BX
        ADD AX,BX
        MOV JDOWN,AX
        RET
     J3:
        MOV HMOV,0C0
        MOV VMOV,0C0
        JMP J2
#ELSE
;JINIT_MSG DB 'Searching for joystick...'
;LEN_JIMSG EQU $-(OFFSET JINIT_MSG)
;        DB '$'
JOYSTICK_INIT:
;        MOV AH,2
;        MOV BH,0
;        MOV DX,12 BY ((80-LEN_JIMSG) SHR 1)
;        INT 010  ; place cursor
;        MOV AH,9
;        LEA DX,JINIT_MSG
;        INT 021
;
        MOV CX,16
        MOV AX,BX,0
     J1:
        PUSH AX,BX,CX
        CALL JOYSTICK
        JNC >J2
        MOV HMOV,080
        MOV VMOV,080
     J2:
        POP CX,BX,AX
        ADD AL,HMOV
        ADC AH,0
        ADD BL,VMOV
        ADC BH,0
        LOOP J1         ; add up
        MOV CL,4
        SHR AX,CL       ; divide to get average
        SHR BX,CL
        MOV HMOV,AL
        MOV VMOV,BL
        DMOV START_JOYVALS,JOYVALS
;
        MOV AH,HMOV
        MOV AL,VMOV     ; assuming joystick is in the middle...
        PUSH AX
        SHR AH,1        ; ...find one-fourth point
        MOV JLEFT,AH
        SHR AL,1
        MOV JUP,AL
        POP AX
        ADD AH,JLEFT
        MOV JRIGHT,AH
        ADD AL,JUP
        MOV JDOWN,AL
;
;        MOV AH,2
;        MOV BH,0
;        MOV DX,12 BY ((80-LEN_JIMSG) SHR 1)
;        INT 010  ; place cursor
;        MOV AX,0A BY ' '
;        XOR BX,BX
;        MOV CX,LEN_JIMSG
;        INT 010  ; erase message
        RET
#ENDIF
;CALIB_CHAR DB 0DF,0C4,016,'_'
;           DB 0BA,0A6,0E0,083
;BUTTON2STILLDOWN DB 0FF,0
JOYSTICK_CALIBRATE:
        CMP MOVEMODE,v_Joystick
        JNE RET
        TEST BUTTONS,020
        JZ >C0
        MOV BUTTON2STILLDOWN,0
        RET
     C0:
        CMP BUTTON2STILLDOWN,0
        JNE RET
        MOV BUTTON2STILLDOWN,0FF
CALIBRATE:
        PUSH JOYVALS
        PUSH JOYVALS[2]
        IN AL,061
        AND AL,0FC
        OUT 061,AL
        PUSH DS
        MOV DS,AX,VIDSEG_MAIN
        MOV ES,AX
        MOV SI,0
        MOV DI,01000*HELP_TXTPG    ; addr of page 2
        MOV CX,80*25
        REP MOVSW
        POP DS
#IF 0
        MOV DI,01000*HELP_TXTPG+160
        MOV CX,80*3
        XOR AX,AX
        REP STOSW
        MOV DI,01000*HELP_TXTPG+160*20
        MOV CX,80*3
        XOR AX,AX
        REP STOSW
        MOV DI,01000*HELP_TXTPG+160*3+7*2
        MOV CX,66
        MOV AX,03DC
        REP STOSW             ; top edge
        MOV W[ES:DI],0               ; UR corner
        MOV DI,01000*HELP_TXTPG+160*20+7*2
        MOV CX,66
        MOV AX,03DF
        REP STOSW             ; bottom edge
        MOV CX,16
        MOV DI,01000*HELP_TXTPG+160*4
     H1:
        XOR AX,AX
        PUSH CX
        MOV CX,7
        REP STOSW
        POP CX
        MOV W[ES:DI],03DB      ; left edge
        ADD DI,2
        PUSH CX
        MOV CX,64
        MOV AX,08F20
        REP STOSW
        POP CX
        MOV W[ES:DI],03DB      ; right edge
        ADD DI,2
        XOR AX,AX
        PUSH CX
        MOV CX,7
        REP STOSW
        POP CX
;        ADD DI,160-2*72
        LOOP H1
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,26 BY 40
        INT 010       ; move cursor off screen
        CALL CALIBDRAW
        MOV AX,5 BY HELP_TXTPG  ; text page 2
        INT 010
        LEA BX,CALIB_CHAR
        CMP VGA,0
        IF NE ADD BX,4
        MOV TEMP,160*12+40*2
        MOV W[OFFSET BUTTON2STILLDOWN],0200
     C1:
        PUSH BX
        CALL JOYSTICK
        POP BX
        MOV AL,VMOV
        MOV CL,4
        SHR AL,CL
        ADD AL,4
        MOV AH,160
        MUL AH
        MOV DI,AX
        MOV AL,HMOV
        SHR AL,1
        AND AL,0FE
        ADD AL,8*2
        MOV AH,0
        ADD DI,AX
        MOV AL,VMOV
        SHR AL,1
        SHR AL,1
        AND AL,3
        XLATB
        CMP DI,TEMP
        JE >C2
        PUSH DI
        XCHG DI,TEMP
        MOV B[ES:01000*HELP_TXTPG][DI],' '
        POP DI
     C2:
        MOV AH,[ES:01000*HELP_TXTPG][DI+1]
        OR AH,0F
        MOV [ES:01000*HELP_TXTPG][DI],AX
        EXTRN CALIBKEY:NEAR
        CALL CALIBKEY
        TEST BUTTONS,020
        JZ >C3
        CMP BUTTON2STILLDOWN,0
        JE C1
        MOV BUTTON2STILLDOWN,0
        DEC BUTTON2STILLDOWN[1]
        JZ >C4
        JMP C1
     C3:
        MOV BUTTON2STILLDOWN,0FF
        JMP C1
     C4:
        POP JOYVALS
        CMP SOUND?,0
        JE >S1
        CMP SOUND_PTR,0
        JE >S1
        IN AL,061
        OR AL,3
        OUT 061,AL
     S1:
        MOV AX,5 BY MAIN_TXTPG
        INT 010     ; back to text page 0
        RET
CAL_ESC:
        ADD SP,2
        JMP C4
CALIBKEY:
        CMP CTRL_BRK_PRESSED?,0
        IF NE JMP EXIT_PROGRAM
        MOV AH,1
        INT 016
        JZ RET
        MOV AH,0
        INT 016
        CMP AH,sc_Esc    ; if Esc pressed, quit calibration
        JE CAL_ESC
        PUSH AX
        MOV AH,2
        INT 016
        TEST AL,3       ; Shift pressed?
        POP AX
        JNZ >A5
        CMP AH,sc_LeftArrow
        JNE >A1
        CMP JLEFT,4
        IF A SUB JLEFT,4
        JMP CALIBDRAW
     A1:
        CMP AH,sc_RightArrow
        JNE >A2
        CMP JRIGHT,256-4*2
        IF B ADD JRIGHT,4
        JMP CALIBDRAW
     A2:
        CMP AH,sc_UpArrow
        JNE >A3
        CMP JUP,16
        IF AE SUB JUP,16
        JMP CALIBDRAW
     A3:
        CMP AH,sc_DownArrow
        JNE >A4
        CMP JDOWN,256-16*2
        IF B ADD JDOWN,16
        JMP CALIBDRAW
     A4:
        NOP
     A5:
        MOV DH,JRIGHT
        SUB DH,JLEFT
        MOV DL,JDOWN
        SUB DL,JUP
        CMP AH,sc_LeftArrow
        JNE >A6
        CMP DH,8
        IF A ADD JLEFT,4
        JMP CALIBDRAW
     A6:
        CMP AH,sc_RightArrow
        JNE >A7
        CMP DH,8
        IF A SUB JRIGHT,4
        JMP CALIBDRAW
     A7:
        CMP AH,sc_UpArrow
        JNE >A8
        CMP DL,32
        IF A ADD JUP,16
        JMP CALIBDRAW
     A8:
        CMP AH,sc_DownArrow
        JNE >A9
        CMP DL,32
        IF A SUB JDOWN,16
        JMP CALIBDRAW
     A9:
        RET
CDK     EQU 03
CLT     EQU 0F
CALIBTEXTH:
        DW 4*160
        DB 'Less  ',13,'sensi-',13,'tive  ',13,0FF,27,'     ',0
        DW 11*160
        DB 'More  ',13,'sensi-',13,'tive  ',13,0FF,'Shft ',27,0
        DW 4*160+74*2
        DB 'Less  ',13,'sensi-',13,'tive  ',13,0FF,26,'     ',0
        DW 11*160+74*2
        DB 'More  ',13,'sensi-',13,'tive  ',13,0FF,'Shft ',26,0
CALIBTEXTV:
        DW 10*2
        DB '      Less sensitive   ',0FF,24,0
        DW 44*2
        DB 0FF,'Shift ',24,0FF,'   More sensitive',0
        DW 19*160+10*2
        DB '      Less sensitive   ',0FF,25,0
        DW 19*160+44*2
        DB 0FF,'Shift ',25,0FF,'   More sensitive',0
CALIBDRAW:
        MOV DI,01000*HELP_TXTPG+160*4+8*2+1
        MOV CX,16
     D1:
        MOV DL,16
        SUB DL,CL
        SHL DL,1
        SHL DL,1
        SHL DL,1
        SHL DL,1
        PUSH CX
        MOV CX,64
     D2:
        MOV DH,64
        SUB DH,CL
        SHL DH,1
        SHL DH,1
        MOV AX,08F8F
        CMP DH,JLEFT
        IF NA MOV AX,04F4F
        CMP DH,JRIGHT
        IF NB MOV AX,04F4F
        CMP DL,JUP
        JNB >D4
     D3:
        MOV AL,01F
        CMP AH,04F
        IF E MOV AL,02F
        JMP >D5
     D4:
        CMP DL,JDOWN
        JNB D3
     D5:
        STOSB
        INC DI
        LOOP D2
        POP CX
        ADD DI,160-64*2
        LOOP D1
;
        PUSH SI,BX
        MOV SI,CALIBTEXTH
        MOV CX,4
    D10:
        LODSW
        ADD AX,01000*HELP_TXTPG+160*2
        MOV DI,AX
        MOV AH,CDK
        MOV BH,CLT
    D11:
        LODSB
        CMP AL,0
        JE >D14
        CMP AL,0FF
        JNE >D12
        XCHG AH,BH
        JMP D11
    D12:
        CMP AL,13
        JNE >D13
        ADD DI,160-6*2
        JMP D11
    D13:
        STOSW
        JMP D11
    D14:
        LOOP D10
;
        MOV CX,4
    D15:
        LODSW
        ADD AX,01000*HELP_TXTPG+160*2
        MOV DI,AX
        MOV AH,CDK
        MOV BH,CLT
    D16:
        LODSB
        CMP AL,0
        JE >D18
        CMP AL,0FF
        JNE >D17
        XCHG AH,BH
        JMP D16
    D17:
        STOSW
        JMP D16
    D18:
        LOOP D15
        POP BX,SI
        RET
#ELSE
        JMP ASKFORCALIB
CALIBVALUL: DW 0,0
CALIBVALLR: DW 0FFFF,0FFFF
CALIBVALCTR: DW 0,0
ASKFORCALIB:
        MOV AH,2
        MOV BH,HELP_TXTPG
        MOV DX,26 BY 40
        INT 010       ; move cursor off screen
;  draw upper-left depiction
        MOV SI,CALIBTEXTUL
        CALL CALIBDRAW
        MOV AX,5 BY HELP_TXTPG  ; text page 2
        INT 010
        CALL CALIBGETBUTTON
        JC >Q1
        DMOV W[CALIBVALUL],JOYVALS
;  draw center depiction
        MOV SI,CALIBTEXTCTR
        CALL CALIBDRAW
        CALL CALIBGETBUTTON
        JC CALIBRESTORE
        DMOV W[CALIBVALCTR],JOYVALS
;  draw lower-right depiction
        MOV SI,CALIBTEXTLR
        CALL CALIBDRAW
        CALL CALIBGETBUTTON
     Q1:JC CALIBRESTORE
        DMOV W[CALIBVALLR],JOYVALS
;
GETAVG  MACRO
        MOV AX,#1
        ADD AX,#2
        SHR AX,1
        MOV #3,AX
#EM
        GETAVG [CALIBVALCTR],   [CALIBVALUL],   JLEFT
        GETAVG [CALIBVALCTR][2],[CALIBVALUL][2],JUP
        GETAVG [CALIBVALCTR],   [CALIBVALLR],   JRIGHT
        GETAVG [CALIBVALCTR][2],[CALIBVALLR][2],JDOWN
        DMOV START_JOYVALS,W[CALIBVALCTR]
CALIBRESTORE:
        POP JOYVALS[2]
        POP JOYVALS
        CMP SOUND?,0
        JE >S1
        CMP SOUND_PTR,0
        JE >S1
        IN AL,061
        OR AL,3
        OUT 061,AL
     S1:
        MOV AX,5 BY MAIN_TXTPG
        INT 010     ; back to text page 0
        RET
CALIBDRAW:
        MOV DI,01000*HELP_TXTPG+6*160+27*2
        MOV CX,13
        XOR AX,AX
     C1:                        ; erase center of screen
        PUSH CX,DI
        MOV CX,26
        REP STOSW
        POP DI,CX
        ADD DI,160
        LOOP C1
     C2:                        ; draw joystick calibration phase
        LODSW
        CMP AX,-1
        JE >C3
        ADD AX,01000*HELP_TXTPG+7*160+29*2
        MOV DI,AX
        MOVSW
        JMP C2
     C3:
        RET
CALIBGETBUTTON:
     B1:
        MOV AH,6
        MOV DL,0FF
        INT 021
        JZ >B2
        CMP AL,27
        JE >B5
     B2:
        CALL JOYSTICK
        TEST BUTTONS,020
        JZ B1                   ; wait for button to be released
     B3:
        MOV AH,6
        MOV DL,0FF
        INT 021
        JZ >B4
        CMP AL,27
        JE >B5
     B4:
        CALL JOYSTICK
        TEST BUTTONS,020
        JNZ B3                   ; wait for button to be pressed
        CLC
        RET
     B5:
        STC
        RET
CALIBTEXTUL:
        DW 0,03020,2,03020,4,03DC
        DW 160+2,03DF,160+4,03020,160+6,03020,160+8,03DC
        DW 160*2+6,03DF,160*2+8,03020,160*2+10,03020,160*2+12,03DC
        DW 160*3+10,03DF,160*3+12,03020,160*3+14,03020,160*3+16,073DC
        DW 160*3+18,07DF,160*3+20,07DF,160*3+22,07DF,160*3+24,07DF
        DW 160*3+26,07DF,160*3+28,07DF,160*3+30,07020
        DW 160*4+12,07020,160*4+14,03DF,160*4+16,03020,160*4+18,03020
        DW 160*4+20,03DC,160*4+22,07DC,160*4+24,07DC,160*4+30,07020
        DW 160*5+12,07020,160*5+18,073DF,160*5+20,03020,160*5+22,03020
        DW 160*5+24,07020,160*5+30,07020
        DW 160*6+12,07020,160*6+18,07DF,160*6+20,07DF,160*6+22,07DF
        DW 160*6+24,07DF,160*6+30,07020
        DW 160*7+12,07020,160*7+14,07DC,160*7+16,07DC,160*7+18,07DC
        DW 160*7+20,07DC,160*7+22,07DC,160*7+24,07DC,160*7+26,07DC
        DW 160*7+28,07DC,160*7+30,07020
        DW 12,3 BY 'M',14,3 BY 'o',16,3 BY 'v',18,3 BY 'e',22,3 BY 'j'
        DW 24,3 BY 'o',26,3 BY 'y',28,3 BY 's',30,3 BY 't'
        DW 32,3 BY 'i',34,3 BY 'c',36,3 BY 'k',40,3 BY 't',42,3 BY 'o'
        DW 160+16,3 BY 'c',160+18,3 BY 'o',160+20,3 BY 'r',160+22,3 BY 'n'
        DW 160+24,3 BY 'e',160+26,3 BY 'r',160+30,3 BY '&',160+34,3 BY 'p'
        DW 160+36,3 BY 'r',160+38,3 BY 'e',160+40,3 BY 's',160+42,3 BY 's'
        DW 160*2+32,3 BY 'b',160*2+34,3 BY 'u',160*2+36,3 BY 't'
        DW 160*2+38,3 BY 't',160*2+40,3 BY 'o',160*2+42,3 BY 'n'
        DW -1,-1
CALIBTEXTCTR:
        DW 160*3+12,07020,160*3+14,07DF,160*3+16,07DF,160*3+18,07DF
        DW 160*3+20,07DF,160*3+22,07DF,160*3+24,07DF,160*3+26,07DF
        DW 160*3+28,07DF,160*3+30,07020
        DW 160*4+12,07020,160*4+18,07DC,160*4+20,07DC,160*4+22,07DC
        DW 160*4+24,07DC,160*4+30,07020
        DW 160*5+12,07020,160*5+18,07020,160*5+20,03020,160*5+22,03020
        DW 160*5+24,07020,160*5+30,07020
        DW 160*6+12,07020,160*6+18,07DF,160*6+20,07DF,160*6+22,07DF
        DW 160*6+24,07DF,160*6+30,07020
        DW 160*7+12,07020,160*7+14,07DC,160*7+16,07DC,160*7+18,07DC
        DW 160*7+20,07DC,160*7+22,07DC,160*7+24,07DC,160*7+26,07DC
        DW 160*7+28,07DC,160*7+30,07020
        DW 4,3 BY 'M',6,3 BY 'o',8,3 BY 'v',10,3 BY 'e',14,3 BY 'j'
        DW 16,3 BY 'o',18,3 BY 'y',20,3 BY 's',22,3 BY 't'
        DW 24,3 BY 'i',26,3 BY 'c',28,3 BY 'k',160+6,3 BY 't'
        DW 160+8,3 BY 'o',160+12,3 BY 'c',160+14,3 BY 'e',160+16,3 BY 'n'
        DW 160+18,3 BY 't',160+20,3 BY 'e',160+22,3 BY 'r'
        DW 160+26,3 BY '&',160*2+6,3 BY 'p',160*2+8,3 BY 'r'
        DW 160*2+10,3 BY 'e',160*2+12,3 BY 's',160*2+14,3 BY 's'
        DW 160*2+18,3 BY 'b',160*2+20,3 BY 'u',160*2+22,3 BY 't'
        DW 160*2+24,3 BY 't',160*2+26,3 BY 'o',160*2+28,3 BY 'n'
        DW -1,-1
CALIBTEXTLR:
        DW 160*3+12,07020,160*3+14,07DF,160*3+16,07DF,160*3+18,07DF
        DW 160*3+20,07DF,160*3+22,07DF,160*3+24,07DF,160*3+26,07DF
        DW 160*3+28,07DF,160*3+30,07020
        DW 160*4+12,07020,160*4+18,07DC,160*4+20,07DC,160*4+22,07DC
        DW 160*4+24,07DC,160*4+30,07020
        DW 160*5+12,07020,160*5+18,07020,160*5+20,03020,160*5+22,03020
        DW 160*5+24,073DC,160*5+30,07020
        DW 160*6+12,07020,160*6+18,07DF,160*6+20,07DF,160*6+22,03DF
        DW 160*6+24,03020,160*6+26,03020,160*6+28,03DC,160*6+30,07020
        DW 160*7+12,07020,160*7+14,07DC,160*7+16,07DC,160*7+18,07DC
        DW 160*7+20,07DC,160*7+22,07DC,160*7+24,07DC,160*7+26,037DC
        DW 160*7+28,03020,160*7+30,03020,160*7+32,03DC
        DW 160*8+30,03DF,160*8+32,03020,160*8+34,03020,160*8+36,03DC
        DW 160*9+34,03DF,160*9+36,03020,160*9+38,03020,160*9+40,03DC
        DW 160*10+38,03DF,160*10+40,03020,160*10+42,03020
        DW 160*8,3 BY 'M',160*8+2,3 BY 'o',160*8+4,3 BY 'v'
        DW 160*8+6,3 BY 'e',160*8+10,3 BY 'j',160*8+12,3 BY 'o'
        DW 160*8+14,3 BY 'y',160*8+16,3 BY 's',160*8+18,3 BY 't'
        DW 160*8+20,3 BY 'i',160*8+22,3 BY 'c',160*8+24,3 BY 'k'
        DW 160*9,3 BY 't',160*9+2,3 BY 'o',160*9+6,3 BY 'c'
        DW 160*9+8,3 BY 'o',160*9+10,3 BY 'r',160*9+12,3 BY 'n'
        DW 160*9+14,3 BY 'e',160*9+16,3 BY 'r',160*9+20,3 BY '&'
        DW 160*10,3 BY 'p',160*10+2,3 BY 'r',160*10+4,3 BY 'e'
        DW 160*10+6,3 BY 's',160*10+8,3 BY 's'
        DW 160*10+12,3 BY 'b',160*10+14,3 BY 'u',160*10+16,3 BY 't'
        DW 160*10+18,3 BY 't',160*10+20,3 BY 'o',160*10+22,3 BY 'n'
        DW -1,-1
#ENDIF
FINDENV:        ; SI = env variable name
        LODSB           ; get string length
        CBW
        MOV CX,AX
        MOV ES,[02C]            ; get environment segment
        XOR DI,DI
     F0:
        PUSH CX,SI
     F1:
        CMP B[DI],0     ; end of this environment variable?
        JE >F2
        CMPSB
        JNE >F2
        LOOP F1
        JE >F9          ; found a match
     F2:
        MOV CX,0FFFF
        XOR AL,AL
        REPNE SCASB     ; find next 0-byte
        POP SI,CX
        CMP B[ES:DI],0     ; second 0-byte found?
        JNE F0          ; nope;  more variables left to check
        STC
        RET
     F9:
        POP CX
        CLC
        RET
AJ_GETDIGIT:    ; Input: SS:SI=string to search   Output: CF=1 if found
     X1:
        MOV AL,[SS:SI]
        INC SI
        SUB AL,'0'
        CMP AL,10
        JB RET         ; found a digit
        CMP SI,BP
        JB X1
        RET
MULTIPORT_STR DB 10,'MULTIPORT='
MULTIPATH_STR DB 10,'MULTIPATH='
MULTICFG_STR  DB  9,'MULTICFG='
AJ_BUFFER EQU 256
     A0:JMP ATARIJOYSTICK_NOT_PRESENT
ATARIJOYSTICK_INIT:
        LEA SI,MULTIPORT_STR
        CALL FINDENV
        MOV BX,0
        JC >A1
        MOV BL,[ES:DI]
        SUB BL,'1'
     A1:
        MOV ES,AX,040
        PUSH W[ES:8][BX]        ; port address of corresponding LPT
        POP MULTIPORT
;
        PUSH BP
        MOV BP,SP
        SUB SP,AJ_BUFFER
        LEA SI,MULTIPATH_STR
        CALL FINDENV
        JC A0
; Copy MULTIPATH environment variable
        MOV SI,DI
        LEA DI,[BP-AJ_BUFFER]
        PUSH DS
        MOV DS,ES
        MOV ES,SS
     A2:
        CMP B[SI],0
        JE >A3
        MOVSB
        JMP A2
     A3:
        CMP B[SI-1],'\'
        JE >A4
        MOV B[ES:DI],'\'
        INC DI
     A4:
        POP DS
        PUSH DI                         ; save ptr to end of path
        LEA SI,MULTICFG_STR
        CALL FINDENV
        JC A0
;
; Copy MULTICFG environment variable onto end of MULTIPATH
        MOV SI,DI
        POP DI
        PUSH DS
        MOV DS,ES
        MOV ES,SS
     A5:
        CMP B[SI],0
        JE >A6
        MOVSB
        JMP A5
     A6:
        MOVSB                   ; copy final 0
; Now, open MULTIJOY config file...
        MOV DS,SS
        LEA DX,[BP-AJ_BUFFER]
        MOV AX,03D00
        INT 021
        POP DS
        JC A0
        MOV BX,AX               ; file handle
        MOV CX,AJ_BUFFER-1      ; byte count
        LEA DX,[BP-AJ_BUFFER]
        PUSH DS
        MOV DS,SS
        MOV AH,03F
        INT 021         ; read file
        POP DS
        MOV AH,03E
        INT 021         ; close file
        IF C JMP ATARIJOYSTICK_NOT_PRESENT
; interpret MULTIJOY config file data
        XOR DX,DX
        LEA SI,[BP-AJ_BUFFER]
     A8:
        CALL AJ_GETDIGIT
        JNC ATARIJOYSTICK_NOT_PRESENT
        MOV AH,[SS:SI]
        INC SI
        SUB AH,'0'              ; second digit?
        CMP AH,9
        JA >A9
        XCHG AL,AH              ; let AH=tens digit, AL=ones digit
        AAD
     A9:
        XOR AH,AH
        MOV BX,AX               ; got the parallel port index.
        MOV CX,2        ; 2 joystick specs per line
    A10:
        CALL AJ_GETDIGIT        ; read joystick number
        JNC ATARIJOYSTICK_NOT_PRESENT
    A11:
        MOV AL,[SS:SI]
        INC SI
        CMP AL,'a'
        IF AE SUB AL,32         ; convert to uppercase
        CMP AL,'L'
        JNE >A12
        MOV DI,0
        JMP >A16
    A12:
        CMP AL,'R'
        JNE >A13
        MOV DI,1
        JMP >A16
    A13:
        CMP AL,'U'
        JNE >A14
        MOV DI,2
        JMP >A16
    A14:
        CMP AL,'D'
        JNE >A15
        MOV DI,3
        JMP >A16
    A15:
        CMP AL,'F'
        JNE >A17
        MOV DI,4
    A16:
        MOV AJ_INDEX[DI],BL
        MOV AJ_BIT[DI],080
        CMP CX,2
        IF E MOV AJ_BIT[DI],020
        INC DX
        JMP >A18
    A17:
        INC SI
        CMP SI,BP
        JB A11
        JMP ATARIJOYSTICK_NOT_PRESENT
    A18:
        LOOP A10
        CMP DX,5
        JB A8
        RET
ATARIJOYSTICK_NOT_PRESENT:
        MOV SP,BP
        POP BP
        MOV MULTIPORT,-1
        RET
